package com.enbatis.mybatisplugs.commons.utils;

import com.enbatis.mybatisplugs.commons.annotation.Exclude;
import com.enbatis.mybatisplugs.commons.sql.Wrapper;
import com.enbatis.mybatisplugs.enums.CreateSqlEnum;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.jdbc.SQL;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

public class BaseSqlProvider<T>  extends SQL {


    @Options
    public String addEntity( @Param("entity")  T entity) {
        Class clazz = entity.getClass();
        String tableName = clazz.getSimpleName();
        String realTableName = LineHumpUtil.humpToLine(tableName);

         return  new SQL(){
            {
                INSERT_INTO(realTableName);
                List<Field> fields = getFields(clazz);
                for (Field field : fields) {
                    field.setAccessible(true);
                    String column = field.getName();
                    VALUES(LineHumpUtil.humpToLine(column), String.format("#{" + column + "}"));
                }
            }
        }.toString();
    }



    @Options
    public String saveBatch(Map map) {
        Class clazz = (Class)map.get("clazz");
        Collection<T> list =(Collection<T>)map.get("list");
        StringBuilder sb = new StringBuilder();
        String tableName = clazz.getSimpleName();

        String realTableName = LineHumpUtil.humpToLine(tableName);
        sb.append("INSERT INTO  "+realTableName+" ( ");

        List<Field> fields = getFields(clazz);

       StringBuilder patten=new StringBuilder("(");

        for (Field field : fields) {
            field.setAccessible(true);
            String column = field.getName();
            sb.append(LineHumpUtil.humpToLine(column)+" ,");
            patten.append("#'{'list[{0}].").append(column).append("},");
        }
        sb.deleteCharAt(sb.length()-1);
        sb.append(" ) ");
        sb.append("VALUES ");
        patten.deleteCharAt(patten.length()-1);
        patten.append(")");
        MessageFormat mf=new MessageFormat(patten.toString());
        for (int i = 0; i < list.size(); i++) {
            sb.append(mf.format(new Object[]{i}));
            if (i < list.size() - 1) {
                sb.append(",");
            }
        }
        return sb.toString();
    }





    @Options
    public String deleteById(Map map) {
        String tableName =(String) map.get("tableName");
        Serializable id = (Serializable)map.get("id");
        CreateSqlEnum createSqlEnum=CreateSqlEnum.DELETE_BY_ID;
        if (null==id||StringUtils.isBlank(tableName)){
            return "";
        }
        return  String.format(createSqlEnum.getSql(),tableName,"id","id");
    }



    private List<Field> getFields(Class clazz) {

        List<Field> fieldList = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            Exclude key = field.getAnnotation(Exclude.class);
            if (key == null) {
                fieldList.add(field);
            }

        }
        return fieldList;
    }
    @Options
    public String getById(String tableName, Serializable id) {
        if (null==id||StringUtils.isBlank(tableName)){
            return "";
        }
        SQL sql = new SQL();
        sql.SELECT("*").FROM(tableName);
        sql.WHERE("id" + "=" + id);
        return sql.toString();
    }


    @Options
    public String list(Wrapper<T> wrapper){

         SQL sql=new SQL();
        Class clazz = wrapper.getEntity().getClass();
        String tableName = clazz.getSimpleName();
        String realTableName = LineHumpUtil.humpToLine(tableName);
        String column=wrapper.getSqlSelect();

          if (StringUtils.isBlank(column)){
              sql.SELECT("*").FROM(realTableName);
          }else{
              sql.SELECT(column).FROM(realTableName);
          }
          String condition =wrapper.getWholeQuerySql();

          if (StringUtils.isNotBlank(condition)){

              String[] con=condition.split("AND");
              for (String s:con) {
                  if (StringUtils.isNotBlank(s.trim())){
                      sql.WHERE(s);
                  }
              }
          }



        String orderBy=wrapper.getOrderBy();
        if (orderBy!=null){
            sql.ORDER_BY(orderBy);
        }
        return  sql.toString();
    }


    @Options
    public String selectCount(@Param("wrapper") Wrapper<T> wrapper){
        StringBuilder sb = new StringBuilder("SELECT COUNT(1) FROM  ");
        Class clazz = wrapper.getEntity().getClass();
        String tableName = clazz.getSimpleName();
        String realTableName = LineHumpUtil.humpToLine(tableName);
        sb.append(realTableName).append(" WHERE 1=1 ");

        sb.append(wrapper.getWholeQuerySql());
        return  sb.toString();
    }


    @Options
    public String update(Map map) {
        T bean = (T)map .get("bean");
        Wrapper<T> wrapper = (Wrapper<T>)map.get("wrapper");
        SQL sql = new SQL();
        Class clazz = bean.getClass();
        String tableName = clazz.getSimpleName();
        String realTableName = LineHumpUtil.humpToLine(tableName);
        sql.UPDATE(realTableName);
        List<Field> fields = getFields(clazz);
        for (Field field : fields) {

            field.setAccessible(true);

            String column = field.getName();

            if (column.equals("id")) {
                continue;
            }
            try {
                Method method= clazz.getMethod("get"+LineHumpUtil.firstCharToBigger(column));
                if (null==method.invoke(bean)){
                    continue;
                }
            }catch (Exception e){
                e.printStackTrace();
            }

            sql.SET(LineHumpUtil.humpToLine(column) + "=" + String.format("#{bean." + column + "}"));
        }

        StringBuilder sb=new StringBuilder(" 1=1 ");

        sb.append(wrapper.getWholeQuerySql());

        sql.WHERE(sb.toString());
        return sql.toString();

    }
    @Options
    public String updateById(Map map) {
        String tableName = (String)map.get("tableName");
        T bean = (T)map.get("bean");
        SQL sql = new SQL();
        String realTableName = LineHumpUtil.humpToLine(tableName);
        sql.UPDATE(realTableName);
        Class clazz=  bean.getClass();
        List<Field> fields = getFields(clazz);
        for (Field field : fields) {
            field.setAccessible(true);
            String column = field.getName();
            if (column.equals("id")) {
                continue;
            }
            try {
                Method method= clazz.getMethod("get"+LineHumpUtil.firstCharToBigger(column));
                if (null==method.invoke(bean)){
                    continue;
                }else{
                    sql.SET(LineHumpUtil.humpToLine(column) + "=" + String.format("#{bean." + column + "}"));
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        boolean it=true;
        for (Field pkField : fields) {
                pkField.setAccessible(true);
                String column = pkField.getName();
                if (column.equals("id")) {
                    it=false;
                    sql.WHERE("id" + "=" + String.format("#{bean.id}"));
                    break;
                }
            }
          if (it){
              sql.WHERE("1=2");
          }
        return sql.toString();

    }

}
